#pragma once

#include <string>
#include <strings.h>

/*网络必要的头文件*/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

/*日志头文件*/
#include "logMessage.hpp"
#include "Protocol.hpp"

#include <unistd.h>

namespace client
{
    using namespace std;
    using namespace protocol;
    class tcpClient
    {
    public:
        tcpClient(const string &serverIp, const uint16_t &serverPort)
            : _socketFd(-1), _serverIp(serverIp), _serverPort(serverPort)
        {
            _socketFd = socket(AF_INET, SOCK_STREAM, 0);
            if (_socketFd == -1)
            { /*客户端通常不需要打印日志*/
                cerr << "socket failed..." << endl;
                exit(-1);
            }
        }

        void start()
        {
            struct sockaddr_in server = getSockaddr_in();
            int n = connect(_socketFd, (struct sockaddr *)&server, sizeof(server));
            if (n == -1)
            {
                cerr << "connect failed..." << endl;
                exit(-2);
            }
            else
            {
                while (true)
                {
                    cout << "Please Input Expression# ";
                    string message;
                    getline(cin, message);
                    Request rqs = parseMessage(message);
                    string rqsStr;
                    rqs.serialize(rqsStr);
                    string send_string = addHeaders(rqsStr);
                    if (send_string.empty())
                        continue;
                    send(_socketFd, send_string.c_str(), send_string.size(), 0);

                    char buffer[1024];
                    string rpsStr;
                    Response rps;
                    if (!getRequest(_socketFd, rpsStr))
                        continue;
                    if (!delHeaders(rpsStr))
                        continue;
                    rps.deserialize(rpsStr);
                    cout << "exitCode: " << rps._exitCode << endl;
                    cout << "result: " << rps._result << endl;
                }
            }
        }

    private:
        /*客户端不关心自己的IP和端口号
         *主要关心服务端的IP和端口号*/
        string _serverIp;
        uint16_t _serverPort;
        int _socketFd;

        /*将用于网络通信的结构体的设置封装成模块
         *由于编译器优化实际上只发生一次拷贝构造*/
        struct sockaddr_in getSockaddr_in()
        {
            struct sockaddr_in server;
            bzero((void *)&server, sizeof(server));
            server.sin_family = AF_INET;
            server.sin_port = htons(_serverPort);
            server.sin_addr.s_addr = inet_addr(_serverIp.c_str());
            return server;
        }

        /*收到的msg无非就是"left oper right"并且没有回车*/
        Request parseMessage(const string &msg)
        {
            int status = 0; /*0:左操作数;1:操作符;2:右操作数*/
            string left, right;
            char oper;
            for (auto &e : msg)
            {
                switch (status)
                {
                case 0:
                {
                    if (!isdigit(e))
                    {
                        status = 2;
                        oper = e;
                    }
                    else
                        left.push_back(e);
                }
                break;
                case 1:
                    status = 2;
                    break;
                case 2:
                    right.push_back(e);
                    break;
                default:
                    break;
                }
            }
            cout << "left: " << left << " right: " << right << " oper: " << oper << endl;
            return Request(stoi(left),stoi(right),oper);
        }
    };
} /*namespace client ends here*/